<?php

namespace App\Services;

use App\Common\SDK\Facade\FenZhangTong;
use App\Common\SDK\Facade\ShanDe;
use App\Common\SDK\Facade\ChinaUms;
use App\Events\RefreshUserInfo;
use App\Models\AgentRevenue;
use App\Models\AgentTopUpOrder;
use App\Models\DailyReportStatistics;
use App\Models\ModelHasPaymentOrder;
use App\Models\PaymentChannelBase;
use App\Models\PaymentChannelFztcashier;
use App\Models\PaymentChannelFztsdwx;
use App\Models\PaymentChannelFztwx;
use App\Models\PaymentChannelFztumswx;
use App\Models\PaymentOrder;
use Carbon\Carbon;
use Illuminate\Database\Eloquent\ModelNotFoundException;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Log;

class PaymentService
{
    public function defray($data)
    {
        // 收银台订单信息
        $paymentOrder = PaymentOrder::query()->create([
            'order_id' => $this->generateOrderId($data['channel']),
            'business_order_id' => $data['out_trade_no'],
            'amount' => $data['amount'],
            'payment_channel' => $data['channel'],
            'subject' => $data['subject'] ?? '',
            'body' => $data['body'] ?? '',
            'remark' => $data['remark'] ?? '',
            'started_at' => Carbon::now()
        ]);
        // 下渠道订单
        $channelMethod = 'defrayChannel' . PaymentOrder::PAYMENT_CHANNEL_ABBREVIATION_MAP[$data['channel']];

        return [
            $paymentOrder,
            $this->{$channelMethod}($data, $paymentOrder)
        ];
    }

    /**
     * 分账通 微信支付
     * @param $data
     * @param PaymentOrder $paymentOrder
     * @return array
     * @throws \Exception
     */
    private function defrayChannelFW($data, PaymentOrder $paymentOrder)
    {
        $transAmt = (string) round($data['amount'] / 100, 2); // 渠道要求字符串
        FenZhangTong::createTransactionOrder([
            'orderNum' => 1,
            'orderList' => [
                [
                    'platOrderNo' => $data['out_trade_no'], // 订单号
                    'platOrderInfo' => $data['body'], // 订单内容
                    'transAmt' => $transAmt, // 金额
                    'guaranteeType' => '2', // 非担保类型
                    'sellerId' => env('FEN_ZHANG_TONG_SDJ_MCHNO'), // 卖方客户编号, 省到家汇总账户
                ]
            ],
        ]);
        FenZhangTong::createPaymentOrder([
            'platPayId' => $data['out_trade_no'],
            'orderType' => PaymentChannelBase::ORDER_TYPE_PAY_ORDER, // 支付订单
            'transAmt' => $transAmt,
            'platOrderNos' => $data['out_trade_no'],
            'notifyUrl' => $data['notify_url'], // 回调地址
            'returnUrl' => $data['return_url'], // 返回地址
        ]);
        $wxEntId = explode(',', env('FEN_ZHANG_TONG_WXENTID'));
        $weChatPayRes = FenZhangTong::weChatPayApplication([
            'payType' => $data['pay_type'],
            'platPayId' => $data['out_trade_no'],
            'custClientIp' => $data['client_id'],
            'openId' => $data['openid'],
            'mpAppId' => $data['app_id'],
            'wxEntId' => $wxEntId[random_int(0, count($wxEntId) - 1)], // 平台微信标识, 随机选择一个
        ]);

        // 创建渠道订单
        $channelOrder = PaymentChannelFztwx::query()->create([
            'plat_order_no' => $data['out_trade_no'],
            'order_type' => PaymentChannelBase::ORDER_TYPE_PAY_ORDER,
            'trans_amt' => $data['amount'],
            'prepay_id' => $weChatPayRes['prepayId'],
            'place_order_response_snapshot' => $weChatPayRes
        ]);
        $channelOrder->paymentOrders()->sync([$paymentOrder['id'] => ['type' => ModelHasPaymentOrder::TYPE_CHANNEL_ORDER]]);

        return $weChatPayRes;
    }

    /**
     * 分账通 银行快捷支付
     * @param $data
     * @param PaymentOrder $paymentOrder
     * @return array
     */
    private function defrayChannelFC($data, PaymentOrder $paymentOrder)
    {
        $transAmt = (string) round($data['amount'] / 100, 2); // 渠道要求字符串
        FenZhangTong::createTransactionOrder([
            'orderNum' => 1,
            'orderList' => [
                [
                    'platOrderNo' => $data['out_trade_no'], // 订单号
                    'platOrderInfo' => $data['body'], // 订单内容
                    'transAmt' => $transAmt, // 金额
                    'guaranteeType' => '2', // 非担保类型
                    'sellerId' => env('FEN_ZHANG_TONG_SDJ_MCHNO'), // 卖方客户编号, 省到家汇总账户
                    'buyerId' => $data['plat_cust_no'] ?? '', // 客户编号
                ]
            ],
        ]);
        FenZhangTong::createPaymentOrder([
            'platPayId' => $data['out_trade_no'],
            'orderType' => PaymentChannelBase::ORDER_TYPE_PAY_ORDER, // 支付订单
            'transAmt' => $transAmt,
            'platOrderNos' => $data['out_trade_no'],
            'platCustNo' => $data['plat_cust_no'] ?? '', // 客户编号 与 交易订单 buyerId 一致
            'notifyUrl' => $data['notify_url'], // 回调地址
            'returnUrl' => $data['return_url'], // 返回地址
        ]);
        // 打开收银台申请
        $cashierPayRes = FenZhangTong::openTheCashierApplication([
            'platPayId' => $data['out_trade_no'],
            'payMethod' => $data['pay_method'],
            'platCustNo' => $data['plat_cust_no'] ?? '', // 客户编号 与 交易订单 buyerId 一致
            'payCardNo' => $data['pay_card_no'] ?? '', // 支付卡号，如上送卡号必须是客户的绑定卡
        ]);

        // 创建渠道订单
        $channelOrder = PaymentChannelFztcashier::query()->create([
            'plat_order_no' => $data['out_trade_no'],
            'order_type' => PaymentChannelBase::ORDER_TYPE_PAY_ORDER,
            'pay_method' => $data['pay_method'],
            'trans_amt' => $data['amount'],
            'place_order_response_snapshot' => $cashierPayRes
        ]);
        $channelOrder->paymentOrders()->sync([$paymentOrder['id'] => ['type' => ModelHasPaymentOrder::TYPE_CHANNEL_ORDER]]);

        return $cashierPayRes;
    }

    /**
     * 杉德 微信支付
     * @param $data
     * @param PaymentOrder $paymentOrder
     * @return array
     * @throws \Exception
     */
    private function defrayChannelSW($data, PaymentOrder $paymentOrder)
    {
        $shandeRes = ShanDe::gateWayOrderPay([
            'head' => [
                'version' => '1.0',
                'method' => 'sandpay.trade.pay', // 因为这个字段,导致不能统一处理 head 部分
                'productId' => '00002020', // 微信公众号
                'accessType' => '1', // 普通商户
                'mid' => env('SHAN_DE_MID'), // 商户号
                'channelType' => '08', // 移动端
                'reqTime' => Carbon::now()->format('YmdHis')
            ],
            'body' => [
                'orderCode' => $data['out_trade_no'],
                'totalAmount' => str_pad($data['amount'], 12, '0', STR_PAD_LEFT),
                'subject' => $data['body'],
                'body' => $data['body'],
                'payMode' => 'sand_wx',
                'payExtra' => json_encode(['subAppid' => $data['app_id'], 'userId' => $data['openid']]),
                'clientIp' => $data['ip'] ?? '',
                'notifyUrl' => $data['notify_url'] ,
                'extend' => json_encode([]),
                'clearCycle' => 3 // TODO 清算模式 ???
            ]
        ]);

        // 创建渠道订单
        $channelOrder = PaymentChannelFztsdwx::query()->create([
            'plat_order_no' => $data['out_trade_no'],
            'order_type' => PaymentChannelFztsdwx::ORDER_TYPE_PAY_ORDER,
            'trans_amt' => $data['amount'],
            'prepay_id' => $shandeRes['prepay_id'],
            'place_order_response_snapshot' => $shandeRes
        ]);
        $channelOrder->paymentOrders()->sync([$paymentOrder['id'] => ['type' => ModelHasPaymentOrder::TYPE_CHANNEL_ORDER]]);

        return json_decode(json_decode($shandeRes['credential'], true)['params'], true);
    }
    /**
     * 银联商务 微信支付
     * @param $data
     * @param PaymentOrder $paymentOrder
     * @return array
     * @throws \Exception
     */
    private function defrayChannelUW($data, PaymentOrder $paymentOrder)
    {
        $umsRes = ChinaUms::gateWayOrderPay([
            'requestTimestamp'=> Carbon::now()->format('Y-m-d H:i:s'), //报文请求时间，格式yyyy-MM-dd HH:mm:ss
            'merOrderId' => $data['out_trade_no'], //商户订单号
            'srcReserve' => $data['out_trade_no'], //请求系统预留字段
            'mid'   => env('CHINA_UMS_MID'), //商户号
            'tid'   => env('CHINA_UMS_TID'), //终端号
            'instMid'   => 'YUEDANDEFAULT', //业务类型
            'totalAmount'   => $data['amount'], //支付总金额，单位分
            'notifyUrl' => $data['notify_url'], //支付结果通知地址
            'returnUrl' => $data['return_url'], //支付后返回地址
            'subAppId' => env('CHINA_UMS_MP_APPID'), //公众号APPID
            'subOpenId' => $data['openid'], //用户子标识 商户自己公众号appid下的用户openid 
            'tradeType'  => 'JSAPI', //交易类型 
        ]);

        
        // 创建渠道订单
        $channelOrder = PaymentChannelFztumswx::query()->create([
            'plat_order_no' => $data['out_trade_no'],
            'order_type' => PaymentChannelFztumswx::ORDER_TYPE_PAY_ORDER,
            'trans_amt' => $data['amount'],
            'prepay_id' => '',
            'place_order_response_snapshot' => $umsRes
        ]);
        $channelOrder->paymentOrders()->sync([$paymentOrder['id'] => ['type' => ModelHasPaymentOrder::TYPE_CHANNEL_ORDER]]);

        return $umsRes['jsPayRequest'];
    }

    /**
     * 生成收银台订单 ID
     * @param $channel
     * @return string
     * @throws \Exception
     */
    private function generateOrderId($channel)
    {
        return PaymentOrder::PAYMENT_CHANNEL_ABBREVIATION_MAP[$channel] . Carbon::now()->format('YmdHisu') . random_int(0, 9);
    }

    /**
     * 处理分账通充值订单 (处理回调 和 主动处理)
     * @param $platPayId string 订单号
     * @param \DateTime|null $payTime 支付时间
     * @param array $notifyData 回调通知数据
     * @param string $channel 支付渠道
     * @return false|mixed
     */
    public function handleFztPaymentTopUp($platPayId, \DateTime $payTime = null, $notifyData = [], $channel = 'wx')
    {
        // 开头部分根据渠道检查是否完成订单, 如果没完成就直接返回
        if ($channel === 'umswx'){
            //银联商务
            $paymentOrderDetail = ChinaUms::getPaymentOrderDetail([
                'requestTimestamp'=> Carbon::now()->format('Y-m-d H:i:s'), //报文请求时间，格式yyyy-MM-dd HH:mm:ss
                'mid'   => env('CHINA_UMS_MID'), //商户号
                'tid'   => env('CHINA_UMS_TID'), //终端号
                'instMid'   => 'YUEDANDEFAULT', //业务类型
                'merOrderId' => $platPayId, //商户订单号
            ]);
            if ((string) $paymentOrderDetail['status'] !== 'TRADE_SUCCESS' || $paymentOrderDetail['errCode'] !== 'SUCCESS') {
                return false;
            }

        }else if ($channel === 'sdwx') {
            // 衫德支付的渠道
            // https://open.sandpay.com.cn/product/detail/43311/43787/43788
            $paymentOrderDetail = ShanDe::getPaymentOrderDetail([
                'head' => [
                    'version' => '1.0',
                    'method' => 'sandpay.trade.query',
                    'productId' => '00002020', // 微信公众号
                    'accessType' => '1', // 1 普通商户接入 2 平台商户接入
                    'mid' => env('SHAN_DE_MID'),
                    'channelType' => '08', // 商户的真实应用场景 07 互联网 08 移动端
                    'reqTime' => Carbon::now()->format('YmdHis')
                ],
                'body' => [
                    'orderCode' => $platPayId,
                ]
            ]);
            if ((string) $paymentOrderDetail['orderStatus'] !== '00' || $paymentOrderDetail['oriRespCode'] !== '000000') {
                return false;
            }
        } else {
            // 分账通渠道
            $paymentOrderDetail = FenZhangTong::getPaymentOrderDetail(['platPayId' => $platPayId]);
            if ((int) $paymentOrderDetail['stat'] !== 1 || $paymentOrderDetail['retCode'] !== '00000') {
                return false;
            }
        }

        // 完成渠道支付订单的情况下, 进行充值
        return Cache::lock('handle_fzt_payment_top_up_' . $platPayId, 10)->get(function () use ($platPayId, $payTime, $notifyData, $channel) {
            // 找到订单
            $paymentOrder = null;
            try {
                $paymentOrder = PaymentOrder::query()
                    ->with(['channelFzt' . $channel, 'businessTopup.agent'])
                    ->where('business_order_id', $platPayId)
                    ->firstOrFail();
                if ($paymentOrder['pay_status'] !== PaymentOrder::PAY_STATUS_GENERATE) {
                    return true;
                }
            } catch (ModelNotFoundException $e) {
                Log::error('业务订单不存在: ' . $platPayId);
                return false;
            }

            /** @var AgentTopUpOrder $agentTopUpOrder */
            $agentTopUpOrder = $paymentOrder->businessTopup[0];
            /** @var PaymentChannelBase $channelOrder */
            $channelOrder = $paymentOrder->{'channelFzt' . $channel}[0];
            // 业务处理
            try {
                \DB::beginTransaction();

                $agentTopUpOrder
                    ->agent
                    ->incrementOrDecrementBalance($agentTopUpOrder['amount'], AgentRevenue::TYPE_TOP_UP, $agentTopUpOrder); // 加充值的钱

                // 每日充值统计
                $payTime === null && $payTime = Carbon::now();
                // TODO 充值赠送暂时没上
                /** @var DailyReportStatistics $dailyReportStatistics */
                $dailyReportStatistics = CacheLockKeyConst::dailyReportStatistics($payTime);
                $dailyReportStatistics->incrementOrDecrementTopUp($agentTopUpOrder['amount']);

                $paymentOrder->update(['payment_at' => $payTime, 'pay_status' => PaymentOrder::PAY_STATUS_SUCCESS]);
                $channelOrder->update(['notify_snapshot' => $notifyData, 'status' => PaymentChannelBase::STATUS_COMPLETE]);
                $agentTopUpOrder->update(['status' => AgentTopUpOrder::STATUS_COMPLETE, ]); // TODO 当有充值赠送时,这里需要保存设置快照

                // 通知客户端刷新信息
                event(new RefreshUserInfo($agentTopUpOrder->agent->getKey()));

                \DB::commit();
            } catch (\Exception $e) {
                \DB::rollBack();
                Log::error($e);
                $paymentOrder->update(['pay_status' => PaymentOrder::PAY_STATUS_FAIL]);
                $channelOrder->update(['notify_snapshot' => $notifyData, 'status' => PaymentChannelBase::STATUS_FAIL]);
                $agentTopUpOrder->update(['status' => AgentTopUpOrder::STATUS_FAIL]);

                return false;
            }

            return true;
        });
    }
    /**
     * 结算卡入驻

     * @param array $params 数据
     * @param string $channel 支付渠道
     * @return false|mixed
     */
    public function  withdrawAccountReg($params, $channel = 'ums')
    {

        // 结算通道
        if ($channel === 'ums'){
            //银联商务
            $res = ChinaUms::openAccount([
                'payexacctno'   => env('CHINA_UMS_OPEN_PAYEXACCTNO'), //企业账号
                'payexacctname'   => env('CHINA_UMS_OPEN_PAYEXACCTNAME'), //企业户名
                'relbankacctname' => $params['cardholder_name'], //姓名
                'certno' => $params['cardholder_id_number'],  //身份证号
                'relbankacctno' => $params['bank_card_account'],  //银行卡号
                'phone' => $params['bank_phone'],  //预留手机号
                'bankname' => $params['bank_name'],   //银行名称
                'bankno' => '', //联行号
            ]);

            if ((string) $res['respCode'] !== '000000') {
                return ['code' => '1000','msg'=> '通道注册失败：'. $res['respMsg'].'['. $res['respCode'] . ']'];
            }
            $params = array_merge($params,['up_sn' => $res['data']['orderid']]);
            return ['code' => '0000','msg'=> '注册成功','params'=> $params ];
        } else {
            return ['code' => '0000','msg'=> '注册成功'];
        }
    } 
}
